package rest

import (
	"fmt"
	"github.com/go-chi/chi/v5"
	"github.com/go-chi/chi/v5/middleware"
	"github.com/go-chi/cors"
	"github.com/go-chi/render"
	"go.uber.org/zap"
	"net/http"
	"originforce.club/bilin-mock/conf"
	"originforce.club/bilin-mock/internal/dao"
	appSubRoute "originforce.club/bilin-mock/internal/rest/routers/app/_id"
	appRoute "originforce.club/bilin-mock/internal/rest/routers/app"
	mockAppRoute "originforce.club/bilin-mock/internal/rest/routers/mock/app"
	"time"
)

type RestServer struct {
	slog *zap.SugaredLogger
	vars *conf.VarsSection
	dao  *db.PgDao
	r    chi.Router
	url  string
}

func NewRestServer(slog *zap.SugaredLogger, pgConfPtr *conf.PgSection, webConfPtr *conf.WebSection, vars *conf.VarsSection) (s *RestServer) {
	s = &RestServer{
		slog: slog.With("module", "RestServer"),
		dao:  db.New(pgConfPtr, slog),
	}
	s.r = chi.NewRouter()
	s.registerRouter()
	s.url = fmt.Sprintf("%s:%s", webConfPtr.Host, webConfPtr.Port)

	return s
}

func (s *RestServer) Run() {
	s.slog.Infof("rest server started on %s ...", s.url)
	if err := http.ListenAndServe(s.url, s.r); err != nil {
		s.slog.Errorf("rest server err %s", err.Error())
	}
}

func (s *RestServer) registerRouter() {

	// A good base middleware stack
	s.r.Use(middleware.RequestID)
	s.r.Use(middleware.RealIP)
	s.r.Use(middleware.Logger)
	s.r.Use(middleware.Recoverer)
	s.r.Use(middleware.Timeout(60 * time.Second))
	s.r.Use(render.SetContentType(render.ContentTypeJSON))
	s.r.Use(cors.Handler(cors.Options{
		// AllowedOrigins:   []string{"https://foo.com"}, // Use this to allow specific origin hosts
		AllowedOrigins: []string{"https://*", "http://*"},
		// AllowOriginFunc:  func(r *http.Request, origin string) bool { return true },
		AllowedMethods:   []string{"GET", "POST", "PUT", "DELETE", "OPTIONS"},
		AllowedHeaders:   []string{"Accept", "Authorization", "Content-Type", "X-CSRF-Token"},
		ExposedHeaders:   []string{"Link"},
		AllowCredentials: false,
		MaxAge:           300, // Maximum value not ignored by any of major browsers
	}))

	pingR := chi.NewRouter()
	pingR.Get("/", func(w http.ResponseWriter, r *http.Request) {
		w.Write([]byte("ok"))
	})
	s.r.Mount("/_ping", pingR)

	appRouter := appRoute.New(s.slog, s.dao, s.vars)
	s.r.Mount("/app", appRouter)
	appSubRouter := appSubRoute.New(s.slog, s.dao, s.vars)
	s.r.Mount("/app/{app_id}/api", appSubRouter)

	mockAppRouter := mockAppRoute.New(s.slog, s.dao, s.vars)
	s.r.Mount("/{app_id}", mockAppRouter)

	return
}
